home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
usenet
/
sources
/
volume90
/
util
/
snap_1_4
/
part03
< prev
next >
Wrap
Internet Message Format
|
1990-02-11
|
59KB
Path: xanth!cs.odu.edu!Amiga-Request
From: Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator)
Newsgroups: comp.sources.amiga
Subject: v90i069: Snap 1.4 - cut, store, and paste between windows, Part03/04
Message-ID: <11377@xanth.cs.odu.edu>
Date: 11 Feb 90 22:51:09 GMT
Sender: tadguy@cs.odu.edu
Reply-To: micke@slaka.sirius.se (Mikael Karlsson)
Lines: 1836
Approved: tadguy@cs.odu.edu (Tad Guy)
X-Mail-Submissions-To: Amiga@cs.odu.edu
X-Post-Discussions-To: comp.sys.amiga
Submitted-by: micke@slaka.sirius.se (Mikael Karlsson)
Posting-number: Volume 90, Issue 069
Archive-name: util/snap-1.4/part03
#!/bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 3 (of 4)."
# Contents: source/handler.s source/minrexx.c source/snapchars.c
# Wrapped by tadguy@xanth on Sun Feb 11 17:48:46 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'source/handler.s' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'source/handler.s'\"
else
echo shar: Extracting \"'source/handler.s'\" \(17796 characters\)
sed "s/^X//" >'source/handler.s' <<'END_OF_FILE'
X include "exec/types.i"
X include "exec/lists.i"
X include "devices/inputevent.i"
X
Xwaiting equ 0
Xselregion equ 1
Xwaitext equ 2
Xselgfx equ 3
Xwaitgfx equ 4
Xinserting equ 5
Xpendsnap equ 6
Xkillbutt equ 7
X
Xnoaction equ 0
Xsnapgfx equ 1
Xsnaptext equ 2
Xsnapinit equ 3
Xinsert equ 4
Xcancel equ 5
X
XLMB equ IECODE_LBUTTON
XLMB_UP equ IECODE_UP_PREFIX+IECODE_LBUTTON
XRMB equ IECODE_RBUTTON
XRMB_UP equ IECODE_UP_PREFIX+IECODE_RBUTTON
XNO_BUTT equ IECODE_NOBUTTON
XLCOM equ IEQUALIFIER_LCOMMAND
XSHIFT equ IEQUALIFIER_LSHIFT+IEQUALIFIER_RSHIFT
X
X
X XDEF _myhandler
X XREF _geta4
X XREF _LVOSignal
X XREF _SysBase
X XREF _MyTask
X XREF _action
X XREF _state
X XREF _modinsert
X XREF _startsignal
X XREF _insertsignal
X XREF _cancelsignal
X XREF _donesignal
X XREF _movesignal
X XREF _clicksignal
X XREF _timersignal
X XREF _initsignal
X XREF _cwsignal
X XREF _textqual ; qualifier for snapping text
X XREF _gfxqual ; -"- -"- -"- gfx
X XREF _insertkey
X XREF _cwkey
X
X SECTION CODE
X
X_myhandler:
X
X; On entry: a0 : Pointer to event list
X; a1 : Pointer to data
X
X; In loop: a1 : Pointer to event
X; d0 : scratch
X
X; Result: d0 : New event list
X
X movem.l a4,-(sp)
X
X jsr _geta4 ; Get offset base a4
X
X move.l a0,a1 ; a1 = Event list = a0
X
X.nextevent
X cmpa.l #0,a1 ; Check for end of list
X beq .done
X
X cmp.w #noaction,_action ; forced noaction - cancel
X bne .notcanceled ; no, we're in action
X move.w #waiting,_state ; no action -> wait state
X bra .dostate
X.notcanceled
X cmp.w #insert,_action ; forced insert - cancel
X bne .dostate ; no
X move.w #inserting,_state ; set correct state
X
X.dostate
X move.w _state,d0
X asl.w #1,d0
X move.w JumpTable(pc,d0.w),d0
XOrigin
X jmp 0(pc,d0.w)
XJumpTable
X dc.w .Waiting-Origin-2
X dc.w .SelRegion-Origin-2
X dc.w .WaitExt-Origin-2
X dc.w .SelGfx-Origin-2
X dc.w .WaitGfx-Origin-2
X dc.w .Insert-Origin-2
X dc.w .PendSnap-Origin-2
X dc.w .CancelTxt-Origin-2
X
X; ********************************************************
X; State: Waiting ~TQ
X; Actions New state Signal
X; TQ PendSnap init
X; LMB+GQ SelGfx init+start
X; LCOM+IKEY Inserting insert
X
X.Waiting
X cmp.b #IECLASS_RAWKEY,ie_Class(a1) ; Is it RAWKEY?
X bne .wait_RAWMOUSE
X
X move.w ie_Qualifier(a1),d0
X and.w _textqual,d0 ; TQ?
X bne .signalinit ; Yes -- init
X
X move.w ie_Qualifier(a1),d0
X and.w #LCOM,d0 ; LCOM?
X beq .EventHandled ; No
X
X move.w _cwkey,d0 ; Control window key
X cmp.w ie_Code(a1),d0
X beq .signalcw
X
X move.w _insertkey,d0
X beq .EventHandled ; Key = 0 -- disabled
X
X cmp.w ie_Code(a1),d0 ; The insert key?
X bne .EventHandled ; No, pass it on
X bra .signalinsert ; Tell'em to insert
X
X.wait_RAWMOUSE
X cmp.b #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE?
X bne .EventHandled ; Nope, pass it on
X
X move.w ie_Qualifier(a1),d0
X and.w _textqual,d0 ; TQ?
X bne .signalinit ; Yes
X
X cmp.w #LMB,ie_Code(a1) ; OK, is it SELECTDOWN?
X bne .EventHandled ; Too bad
X
X move.w ie_Qualifier(a1),d0
X and.w _gfxqual,d0 ; GQ?
X beq .EventHandled ; No, not interested
X
X; Handle event LMB+GQ
X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event
X move.w #snapgfx,_action ; action snapgfx;
X move.w #selgfx,_state ; state selgfx
X move.l _initsignal,d0 ; Signal init and
X or.l _startsignal,d0 ; start
X bra SignalTask
X
X.signalinit
X move.w #pendsnap,_state
X move.w #snapinit,_action
X move.l _initsignal,d0 ; Signal start
X bsr Signal
X bra .PendSnap
X
X
X; *******************************************************
X; State: PendSnap TQ
X; Actions New state Signal
X; ~TQ Waiting cancel
X; LCOM+IKEY Inserting insert
X; LMB SelRegion start
X; RMB Inserting insert
X
X.PendSnap
X cmp.b #IECLASS_RAWKEY,ie_Class(a1) ; RAWKEY?
X bne .ps_RAWMOUSE
X move.w ie_Qualifier(a1),d0
X and.w _textqual,d0 ; TQ?
X bne .ps_IKEY ; Still down, continue
X
X;Handle event ~TQ
X.ps_TQ
X move.w #noaction,_action ; no action
X move.w #waiting,_state ; state waiting
X move.l _cancelsignal,d0 ; snap cancelled
X bra SignalTask
X
X.ps_IKEY
X move.w ie_Qualifier(a1),d0
X and.w #LCOM,d0 ; LCOM?
X beq .EventHandled ; No
X
X move.w _cwkey,d0 ; Control window key
X cmp.w ie_Code(a1),d0
X beq .signalcw
X
X move.w _insertkey,d0
X beq .EventHandled ; Key = 0 -- disabled
X
X cmp.w ie_Code(a1),d0 ; The insert key?
X bne .EventHandled ; No, pass it on
X bra .signalinsert ; Tell'em to insert
X
X.ps_RAWMOUSE
X cmp.b #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE?
X bne .EventHandled ; Nope, pass it on
X
X move.w ie_Qualifier(a1),d0 ; Might be TQ going up.
X and.w _textqual,d0 ; TQ?
X beq .ps_TQ
X
X cmp.w #LMB,ie_Code(a1) ; OK, is it SELECTDOWN?
X bne .ps_RMB ; Too bad
X
X; Handle event LMB+TQ
X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event
X move.w #snaptext,_action ; action snaptext
X move.w #selregion,_state ; state selregion
X move.l _startsignal,d0 ; start
X bra SignalTask
X
X.ps_RMB
X cmp.w #RMB,ie_Code(a1) ; MENUDOWN
X bne .EventHandled
X
X; Handle event RMB+TQ
X.signalinsert
X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event
X
X move.w #0,_modinsert
X move.w ie_Qualifier(a1),d0
X and.w #SHIFT,d0 ; SHIFT?
X beq .NonModified ; No
X move.w #1,_modinsert
X.NonModified
X move.w #insert,_action
X move.w #inserting,_state
X move.l _insertsignal,d0 ; and insert
X bra SignalTask
X
X.signalcw
X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event
X move.w #noaction,_action
X move.w #waiting,_state
X move.l _cancelsignal,d0 ; Exit pending snap
X or.l _cwsignal,d0 ; and tell'em to open window
X bra SignalTask
X
X
X; *******************************************************
X; State: SelRegion LMB+TQ
X; Actions New state Signal
X; ~TQ Waiting cancel
X; ~LMB WaitExt
X; MOVE SelRegion move
X; RMB SelRegion click
X; ~RMB SelRegion Needs no action
X; TIMER SelRegion timer
X
X.SelRegion
X cmp.b #IECLASS_TIMER,ie_Class(a1) ; Timer event?
X bne .sr_RAWKEY
X
X;Handle timer event
X move.l _timersignal,d0
X bra SignalTask
X
X.sr_RAWKEY
X cmp.b #IECLASS_RAWKEY,ie_Class(a1) ; RAWKEY?
X bne .sr_LMB_UP
X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event
X move.w ie_Qualifier(a1),d0
X and.w _textqual,d0 ; TQ?
X bne .EventHandled ; Still down, continue
X
X;Handle event ~TQ
X.sr_TQ
X move.w #cancel,_action ; no action
X move.w #killbutt,_state ; state waiting
X move.l _cancelsignal,d0 ; snap cancelled
X bra SignalTask
X
X.sr_LMB_UP
X cmp.b #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE?
X bne .EventHandled ; Nope, pass it on
X
X move.w ie_Qualifier(a1),d0 ; Might be TQ going up.
X and.w _textqual,d0 ; TQ?
X beq .sr_TQ
X
X cmp.w #LMB_UP,ie_Code(a1) ; SELECTUP
X bne .sr_MOVE ; no, check for move
X
X; Handle event ~LMB
X move.w #waitext,_state ; state waitext
X bra KillEvent
X
X.sr_MOVE
X cmp.w #NO_BUTT,ie_Code(a1) ; MOVE
X bne .sr_RMB ; No, check for RMB
X move.w ie_Qualifier(a1),d0
X and.w #IEQUALIFIER_RELATIVEMOUSE,d0 ; RELATIVEMOUSE
X beq .sr_RMB
X
X; Handle event MOVE
X move.l _movesignal,d0
X bra SignalTask
X
X.sr_RMB
X cmp.w #RMB,ie_Code(a1) ; MENUDOWN
X bne .EventHandled ; No, not interested
X
X; Handle event RMB
X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event
X move.l _clicksignal,d0
X bra SignalTask
X
X; ***************************************************
X; State WaitExt TQ
X; Actions New state Signal
X; ~TQ Waiting done
X; LMB SelRegion click
X; MOVE WaitExt No action needed.
X; RMB Inserting done & insert
X; TIMER WaitExt timer
X
X.WaitExt
X cmp.b #IECLASS_TIMER,ie_Class(a1) ; Timer event?
X bne .we_RAWKEY
X
X;Handle timer event
X move.l _timersignal,d0
X bra SignalTask
X
X.we_RAWKEY
X cmp.b #IECLASS_RAWKEY,ie_Class(a1) ; RAWKEY?
X bne .we_LMB
X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event
X move.w ie_Qualifier(a1),d0
X and.w _textqual,d0 ; TQ?
X bne .EventHandled ; Still down, continue
X
X;Handle event ~TQ
X.we_TQ
X move.w #noaction,_action ; no action
X move.w #waiting,_state ; state waiting
X move.l _donesignal,d0 ; snap finished
X bra SignalTask
X
X.we_LMB
X cmp.b #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE?
X bne .EventHandled ; Nope, pass it on
X
X move.w ie_Qualifier(a1),d0 ; Might be TQ going up.
X and.w _textqual,d0 ; TQ?
X beq .we_TQ ; No.
X
X cmp.w #LMB,ie_Code(a1) ; SELECTDOWN
X bne .we_RMB ; no, check for RMB
X
X; Handle event LMB
X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event
X move.w #selregion,_state ; state waitext
X move.l _clicksignal,d0 ; Extend selection
X bra SignalTask
X
X.we_RMB
X cmp.w #RMB,ie_Code(a1) ; MENUDOWN
X bne .EventHandled ; No, not interested
X
X; Handle event RMB
X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event
X move.w #insert,_action
X move.w #inserting,_state
X move.l _donesignal,d0
X or.l _insertsignal,d0
X bra SignalTask
X
X; *******************************************************
X; State: SelGfx LMB+GQ
X; Actions New state Signal
X; ~GQ Waiting cancel
X; ~LMB WaitGfx
X; MOVE SelGfx move
X; TIMER SelGfx timer
X; RMB SelGfx removed
X
X.SelGfx
X cmp.b #IECLASS_TIMER,ie_Class(a1) ; Timer event?
X bne .sg_RAWKEY
X
X;Handle timer event
X move.l _timersignal,d0
X bra SignalTask
X
X.sg_RAWKEY
X cmp.b #IECLASS_RAWKEY,ie_Class(a1) ; RAWKEY?
X bne .sg_LMB_UP
X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event
X move.w ie_Qualifier(a1),d0
X and.w _gfxqual,d0 ; GQ?
X bne .EventHandled ; Still down, continue
X
X;Handle event ~GQ
X.sg_GQ
X move.w #cancel,_action ; cancelling snap
X move.w #killbutt,_state ; Kill obsolete button
X move.l _cancelsignal,d0 ; snap cancelled
X bra SignalTask
X
X.sg_LMB_UP
X cmp.b #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE?
X bne .EventHandled ; Nope, pass it on
X
X move.w ie_Qualifier(a1),d0 ; Might be GQ going up.
X and.w _gfxqual,d0 ; GQ?
X beq .sg_GQ
X
X cmp.w #LMB_UP,ie_Code(a1) ; SELECTUP
X bne .sg_MOVE ; no, check for move
X
X; Handle event ~LMB
X move.w #waitgfx,_state ; state waitext
X bra KillEvent
X
X.sg_MOVE
X cmp.w #NO_BUTT,ie_Code(a1) ; MOVE
X bne .EventHandled ; No, check for RMB
X move.w ie_Qualifier(a1),d0
X and.w #IEQUALIFIER_RELATIVEMOUSE,d0 ; RELATIVEMOUSE
X beq .EventHandled
X
X; Handle event MOVE
X move.l _movesignal,d0
X bra SignalTask
X
X.sg_RMB
X bra KillEvent
X
X; ***************************************************
X; State WaitGfx GQ
X; Actions New state Signal
X; ~GQ Waiting done
X; LMB SelGfx click
X; MOVE WaitGfx No action needed.
X; TIMER WaitGfx timer
X; RMB WaitGfx -- remove event
X
X.WaitGfx
X cmp.b #IECLASS_TIMER,ie_Class(a1) ; Timer event?
X bne .wg_RAWKEY
X
X;Handle timer event
X move.l _timersignal,d0
X bra SignalTask
X
X.wg_RAWKEY
X cmp.b #IECLASS_RAWKEY,ie_Class(a1) ; RAWKEY?
X bne .wg_LMB
X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event
X move.w ie_Qualifier(a1),d0
X and.w _gfxqual,d0 ; GQ?
X bne .EventHandled ; Still down, continue
X
X;Handle event ~GQ
X.wg_GQ
X move.w #noaction,_action ; no action
X move.w #waiting,_state ; state waiting
X move.l _donesignal,d0 ; snap finished
X bra SignalTask
X
X.wg_LMB
X cmp.b #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE?
X bne .EventHandled ; Nope, pass it on
X
X move.w ie_Qualifier(a1),d0 ; Might be GQ going up
X and.w _gfxqual,d0 ; GQ?
X beq .wg_GQ
X
X cmp.w #LMB,ie_Code(a1) ; SELECTDOWN
X bne .wg_RMB ; no -- finished
X
X; Handle event LMB
X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event
X move.w #selgfx,_state ; state waitext
X move.l _clicksignal,d0 ; Extend selection
X bra SignalTask
X
X.wg_RMB
X cmp.w #NO_BUTT,ie_Code(a1) ; Any button?
X beq .EventHandled ; No, moves are ok
X
X bra KillEvent
X
X
X; ***************************************************
X; State CancelTxt
X; Make sure that the Button Up event that we've got
X; hanging around doesn't get through.
X
X.CancelTxt
X cmp.b #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE?
X bne .EventHandled ; Nope, just pass it on
X
X cmp.w #LMB_UP,ie_Code(a1) ; The button?
X bne .EventHandled ; No
X
X move.w #noaction,_action
X move.w #waiting,_state
X bra KillEvent
X
X; ***************************************************
X; State Insert
X; Snap actions are removed, the rest are passed along.
X
X.Insert
X cmp.b #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE?
X bne .EventHandled ; Nope, pass it on
X
X cmp.w #LMB,ie_Code(a1) ; Left mouse button
X bne .insert_TQ ; No -- just kill
X
X move.w #noaction,_action ; Cancel paste
X
X.insert_TQ
X move.w ie_Qualifier(a1),d0
X and.w _textqual,d0 ; TQ?
X beq .EventHandled ; no
X
X cmp.w #NO_BUTT,ie_Code(a1) ; Any button?
X beq .EventHandled ; No, moves are ok
X
XKillEvent:
X move.b #IECLASS_NULL,ie_Class(a1) ; Kill event
X bra .EventHandled
X
XSignalTask:
X bsr Signal
X
X.EventHandled
X move.l ie_NextEvent(a1),a1 ; Get next event
X bra .nextevent
X
X.done
X movem.l (sp)+,a4
X move.l a0,d0
X rts
X
XSignal:
X movem.l a0-a2/a6,-(sp)
X move.l _MyTask,a1
X move.l _SysBase,a6 ; Get ExecBase for Signal
X jsr _LVOSignal(a6)
X movem.l (sp)+,a0-a2/a6
X rts
X
X end
END_OF_FILE
if test 17796 -ne `wc -c <'source/handler.s'`; then
echo shar: \"'source/handler.s'\" unpacked with wrong size!
fi
# end of 'source/handler.s'
fi
if test -f 'source/minrexx.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'source/minrexx.c'\"
else
echo shar: Extracting \"'source/minrexx.c'\" \(15411 characters\)
sed "s/^X//" >'source/minrexx.c' <<'END_OF_FILE'
X#ifdef SNAPREXX
X/*
X * This is an example of how REXX messages might be handled. This is
X * a `minimum' example that both accepts asynchronous REXX messages and
X * can request REXX service.
X *
X * Read this entire file! It's short enough.
X *
X * It is written in such a fashion that it can be attached to a program
X * with a minimum of fuss. The only external symbols it makes available
X * are the seven functions and RexxSysBase.
X *
X * This code is by Radical Eye Software, but it is put in the public
X * domain. I would appreciate it if the following string was left in
X * both as a version check and as thanks from you for the use of this
X * code.
X *
X * If you modify this file for your own use, don't bump the version
X * number; add a suffix, such as 1.0a or 1.0.3 or something, so we
X * don't have fake `versions' floating around.
X */
Xstatic char *blurb = "Radical Eye MinRexx 0.4" ;
X/*
X * We read in our own personal little include.
X */
X#include "minrexx.h"
X/*
X * All of our local globals, hidden from sight.
X */
Xstatic struct MsgPort *rexxPort ; /* this is *our* rexx port */
Xstatic int bringerdown ; /* are we trying to shut down? */
Xstatic struct rexxCommandList *globalrcl ; /* our command association list */
Xstatic long stillNeedReplies ; /* how many replies are pending? */
Xstatic long rexxPortBit ; /* what bit to wait on for Rexx? */
Xstatic char *extension ; /* the extension for macros */
Xstatic int (*userdisp)() ; /* the user's dispatch function */
Xstatic struct RexxMsg *oRexxMsg ; /* the outstanding Rexx message */
X/*
X * Our library base. Don't you dare close this!
X */
Xstruct RxsLib *RexxSysBase ;
X/*
X * This is the main entry point into this code.
X */
Xlong upRexxPort(s, rcl, exten, uf)
X/*
X * The first argument is the name of your port to be registered;
X * this will be used, for instance, with the `address' command of ARexx.
X */
Xchar *s ;
X/*
X * The second argument is an association list of command-name/user-data
X * pairs. It's an array of struct rexxCommandList, terminated by a
X * structure with a NULL in the name field. The commands are case
X * sensitive. The user-data field can contain anything appropriate,
X * perhaps a function to call or some other data.
X */
Xstruct rexxCommandList *rcl ;
X/*
X * The third argument is the file extension for ARexx macros invoked
X * by this program. If you supply this argument, any `primitive' not
X * in the association list rcl will be sent out to ARexx for
X * interpretation, thus allowing macro programs to work just like
X * primitives. If you do not want this behavior, supply a `NULL'
X * here, and those commands not understood will be replied with an
X * error value of RXERRORNOCMD.
X */
Xchar *exten ;
X/*
X * The fourth argument is the user dispatch function. This function
X * will *only* be called from rexxDisp(), either from the user calling
X * this function directly, or from dnRexxPort(). Anytime a command
X * match is found in the association list, this user-supplied function
X * will be called with two arguments---the Rexx message that was
X * received, and a pointer to the association pair. This function
X * should return a `1' if the message was replied to by the function
X * and a `0' if the default success code of (0, 0) should be returned.
X * Note that the user function should never ReplyMsg() the message;
X * instead he should indicate the return values with replyRexxCmd();
X * otherwise we lose track of the messages that still lack replies.
X */
Xint (*uf)() ;
X/*
X * upRexxPort() returns the signal bit to wait on for Rexx messages.
X * If something goes wrong, it simply returns a `0'. Note that this
X * function is safe to call multiple times because we check to make
X * sure we haven't opened already. It's also a quick way to change
X * the association list or dispatch function.
X */
X{
X struct MsgPort *FindPort() ;
X struct MsgPort *CreatePort() ;
X
X/*
X * Some basic error checking.
X */
X if (rcl == NULL || uf == NULL)
X return(0L) ;
X/*
X * If we aren't open, we make sure no one else has opened a port with
X * this name already. If that works, and the createport succeeds, we
X * fill rexxPortBit with the value to return.
X *
X * Note that rexxPortBit will be 0 iff rexxPort is NULL, so the check
X * for rexxPort == NULL also insures that our rexxPortBit is 0.
X */
X if (rexxPort == NULL) {
X Forbid() ;
X if (FindPort(s)==NULL)
X rexxPort = CreatePort(s, 0L) ;
X Permit() ;
X if (rexxPort != NULL)
X rexxPortBit = 1L << rexxPort->mp_SigBit ;
X }
X/*
X * Squirrel away these values for our own internal access, and return
X * the wait bit.
X */
X globalrcl = rcl ;
X extension = exten ;
X userdisp = uf ;
X return(rexxPortBit) ;
X}
X/*
X * This function closes the rexx library, but only if it is open
X * and we aren't expecting further replies from REXX. It's
X * *private*, but it doesn't have to be; it's pretty safe to
X * call anytime.
X */
Xstatic void closeRexxLib() {
X if (stillNeedReplies == 0 && RexxSysBase) {
X CloseLibrary(RexxSysBase) ;
X RexxSysBase = NULL ;
X }
X}
X/*
X * This function closes down the Rexx port. It is always safe to
X * call, and should *definitely* be made a part of your cleanup
X * routine. No arguments and no return. It removes the Rexx port,
X * replies to all of the messages and insures that we get replies
X * to all the ones we sent out, closes the Rexx library, deletes the
X * port, clears a few flags, and leaves.
X */
Xvoid dnRexxPort() {
X if (rexxPort) {
X RemPort(rexxPort) ;
X bringerdown = 1 ;
X/*
X * A message still hanging around? We kill it off.
X */
X if (oRexxMsg) {
X oRexxMsg->rm_Result1 = RXERRORIMGONE ;
X ReplyMsg(oRexxMsg) ;
X oRexxMsg = NULL ;
X }
X while (stillNeedReplies) {
X WaitPort(rexxPort) ;
X dispRexxPort() ;
X }
X closeRexxLib() ;
X DeletePort(rexxPort) ;
X rexxPort = NULL ;
X }
X rexxPortBit = 0 ;
X}
X/*
X * Here we dispatch any REXX messages that might be outstanding.
X * This is the main routine for handling Rexx messages.
X * This function is fast if no messages are outstanding, so it's
X * pretty safe to call fairly often.
X *
X * If we are bring the system down and flushing messages, we reply
X * with a pretty serious return code RXERRORIMGONE.
X *
X * No arguments, no returns.
X */
Xvoid dispRexxPort() {
X register struct RexxMsg *RexxMsg ;
X int cmdcmp() ;
X register struct rexxCommandList *rcl ;
X register char *p ;
X register int dontreply ;
X
X/*
X * If there's no rexx port, we're out of here.
X */
X if (rexxPort == NULL)
X return ;
X/*
X * Otherwise we have our normal loop on messages.
X */
X while (RexxMsg = (struct RexxMsg *)GetMsg(rexxPort)) {
X/*
X * If we have a reply to a message we sent, we look at the second
X * argument. If it's set, it's a function we are supposed to call
X * so we call it. Then, we kill the argstring and the message
X * itself, decrement the outstanding count, and attempt to close
X * down the Rexx library. Note that this call only succeeds if
X * there are no outstanding messages. Also, it's pretty quick, so
X * don't talk to me about efficiency.
X */
X if (RexxMsg->rm_Node.mn_Node.ln_Type == NT_REPLYMSG) {
X if (RexxMsg->rm_Args[1]) {
X ((int (*)())(RexxMsg->rm_Args[1]))(RexxMsg) ;
X }
X DeleteArgstring(RexxMsg->rm_Args[0]) ;
X DeleteRexxMsg(RexxMsg) ;
X stillNeedReplies-- ;
X closeRexxLib() ;
X/*
X * The default case is we got a message and we need to check it for
X * primitives. We skip past any initial tabs or spaces and initialize
X * the return code fields.
X */
X } else {
X p = (char *)RexxMsg->rm_Args[0] ;
X while (*p > 0 && *p <= ' ')
X p++ ;
X RexxMsg->rm_Result1 = 0 ;
X RexxMsg->rm_Result2 = 0 ;
X/*
X * If somehow the reply is already done or postponed, `dontreply' is
X * set.
X */
X dontreply = 0 ;
X/*
X * If the sky is falling, we just blow up and replymsg.
X */
X if (bringerdown) {
X RexxMsg->rm_Result1 = RXERRORIMGONE ;
X/*
X * Otherwise we cdr down our association list, comparing commands,
X * until we get a match. If we get a match, we call the dispatch
X * function with the appropriate arguments, and break out.
X */
X } else {
X oRexxMsg = RexxMsg ;
X for (rcl = globalrcl; rcl->name; rcl++) {
X if (cmdcmp(rcl->name, p) == 0) {
X userdisp(RexxMsg, rcl, p+strlen(rcl->name)) ;
X break ;
X }
X }
X/*
X * If we broke out, rcl will point to the command we executed; if we
X * are at the end of the list, we didn't understand the command. In
X * this case, if we were supplied an extension in upRexxPort, we know
X * that we should send the command out, so we do so, synchronously.
X * The synchronous send takes care of our reply. If we were given a
X * NULL extension, we bitch that the command didn't make sense to us.
X */
X if (rcl->name == NULL) {
X if (extension) {
X syncRexxCmd(RexxMsg->rm_Args[0], RexxMsg) ;
X dontreply = 1 ;
X } else {
X RexxMsg->rm_Result1 = RXERRORNOCMD ;
X }
X }
X }
X/*
X * Finally, reply if appropriate.
X */
X oRexxMsg = NULL ;
X if (! dontreply)
X ReplyMsg(RexxMsg) ;
X }
X }
X}
X/*
X * This is the function we use to see if the command matches
X * the command string. Not case sensitive, and the real command only
X * need be a prefix of the command string. Make sure all commands
X * are given in lower case!
X */
Xstatic int cmdcmp(c, m)
Xregister char *c, *m ;
X{
X while (*c && ((*c == *m) || (*c == *m + 32 && ('a' <= *c && *c <= 'z')))) {
X c++ ;
X m++ ;
X }
X return(*c) ;
X}
X/*
X * Opens the Rexx library if unopened. Returns success (1) or
X * failure (0). This is another function that is *private* but
X * that doesn't have to be.
X */
Xstatic int openRexxLib() {
X if (RexxSysBase)
X return(1) ;
X return((RexxSysBase = (struct RxsLib *)OpenLibrary(RXSNAME, 0L)) != NULL) ;
X}
X/*
X * This is the general ARexx command interface, but is not the one
X * you will use most of the time; ones defined later are easier to
X * understand and use. But they all go through here.
X */
Xstruct RexxMsg *sendRexxCmd(s, f, p1, p2, p3)
Xchar *s ;
X/*
X * The first parameter is the command to send to Rexx.
X */
Xint (*f)() ;
X/*
X * The second parameter is either NULL, indicating that the command
X * should execute asynchronously, or a function to be called when the
X * message we build up and send out here finally returns. Please note
X * that the function supplied here could be called during cleanup after
X * a fatal error, so make sure it is `safe'. This function always is
X * passed one argument, the RexxMsg that is being replied.
X */
XSTRPTR p1, p2, p3 ;
X/*
X * These are up to three arguments to be stuffed into the RexxMsg we
X * are building up, making the values available when the message is
X * finally replied to. The values are stuffed into Args[2]..Args[4].
X */
X{
X struct RexxMsg *CreateRexxMsg() ;
X STRPTR CreateArgstring() ;
X register struct MsgPort *rexxport ;
X register struct RexxMsg *RexxMsg ;
X
X/*
X * If we have too many replies out there, we just return failure.
X * Note that you should check the return code to make sure your
X * message got out! Then, we forbid, and make sure that:
X * - we have a rexx port open
X * - Rexx is out there
X * - the library is open
X * - we can create a message
X * - we can create an argstring
X *
X * If all of these succeed, we stuff a few values and send the
X * message, permit, and return.
X */
X if (rexxPort == NULL || stillNeedReplies > MAXRXOUTSTANDING-1)
X return(NULL) ;
X RexxMsg = NULL ;
X if (openRexxLib() && (RexxMsg =
X CreateRexxMsg(rexxPort, extension, rexxPort->mp_Node.ln_Name)) &&
X (RexxMsg->rm_Args[0] = CreateArgstring(s, (long)strlen(s)))) {
X RexxMsg->rm_Action = RXCOMM ;
X RexxMsg->rm_Args[1] = (STRPTR)f ;
X RexxMsg->rm_Args[2] = p1 ;
X RexxMsg->rm_Args[3] = p2 ;
X RexxMsg->rm_Args[4] = p3 ;
X RexxMsg->rm_Node.mn_Node.ln_Name = RXSDIR ;
X Forbid() ;
X if (rexxport = FindPort(RXSDIR))
X PutMsg(rexxport, RexxMsg) ;
X Permit() ;
X if (rexxport) {
X stillNeedReplies++ ;
X return(RexxMsg) ;
X } else
X DeleteArgstring(RexxMsg->rm_Args[0]) ;
X }
X if (RexxMsg)
X DeleteRexxMsg(RexxMsg) ;
X closeRexxLib() ;
X return(NULL) ;
X}
X/*
X * This function is used to send out an ARexx message and return
X * immediately. Its single parameter is the command to send.
X */
Xstruct RexxMsg *asyncRexxCmd(s)
Xchar *s ;
X{
X return(sendRexxCmd(s, NULL, NULL, NULL, NULL)) ;
X}
X/*
X * This function sets things up to reply to the message that caused
X * it when we get a reply to the message we are sending out here.
X * But first the function we pass in, which actually handles the reply.
X * Note how we get the message from the Args[2]; Args[0] is the command,
X * Args[1] is this function, and Args[2]..Args[4] are any parameters
X * passed to sendRexxCmd() as p1..p3. We pass the result codes right
X * along.
X */
Xstatic void replytoit(msg)
Xregister struct RexxMsg *msg ;
X{
X register struct RexxMsg *omsg ;
X
X omsg = (struct RexxMsg *)(msg->rm_Args[2]) ;
X replyRexxCmd(omsg, msg->rm_Result1, msg->rm_Result2, NULL) ;
X ReplyMsg(omsg) ;
X}
X/*
X * This function makes use of everything we've put together so far,
X * and functions as a synchronous Rexx call; as soon as the macro
X * invoked here returns, we reply to `msg', passing the return codes
X * back.
X */
Xstruct RexxMsg *syncRexxCmd(s, msg)
Xchar *s ;
Xstruct RexxMsg *msg ;
X{
X return(sendRexxCmd(s, (APTR)&replytoit, msg, NULL, NULL)) ;
X}
X/*
X * There are times when you want to pass back return codes or a
X * return string; call this function when you want to do that,
X * and return `1' from the user dispatch function so the main
X * event loop doesn't reply (because we reply here.) This function
X * always returns 1.
X */
Xvoid replyRexxCmd(msg, primary, secondary, string)
X/*
X * The first parameter is the message we are replying to.
X */
Xregister struct RexxMsg *msg ;
X/*
X * The next two parameters are the primary and secondary return
X * codes.
X */
Xregister long primary, secondary ;
X/*
X * The final parameter is a return string. This string is only
X * returned if the primary return code is 0, and a string was
X * requested.
X *
X * We also note that we have replied to the message that came in.
X */
Xregister char *string ;
X{
X STRPTR CreateArgstring() ;
X
X/*
X * Note how we make sure the Rexx Library is open before calling
X * CreateArgstring . . . and we close it down at the end, if possible.
X */
X if (primary == 0 && (msg->rm_Action & (1L << RXFB_RESULT))) {
X if (string && openRexxLib())
X secondary = (long)CreateArgstring(string, (long)strlen(string)) ;
X else
X secondary = 0L ;
X }
X msg->rm_Result1 = primary ;
X msg->rm_Result2 = secondary ;
X closeRexxLib() ;
X}
X#endif
END_OF_FILE
if test 15411 -ne `wc -c <'source/minrexx.c'`; then
echo shar: \"'source/minrexx.c'\" unpacked with wrong size!
fi
# end of 'source/minrexx.c'
fi
if test -f 'source/snapchars.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'source/snapchars.c'\"
else
echo shar: Extracting \"'source/snapchars.c'\" \(21526 characters\)
sed "s/^X//" >'source/snapchars.c' <<'END_OF_FILE'
X/* Auto: make
X*/
X
XIMPORT struct SnapRsrc *SnapRsrc;
X
X#define COPY 0xC0L
X#define INVCOPY 0x30L
X#define CopyChar(_x, _y, _m) \
X BltBitMap(&MyBM, (LONG)_x, (LONG)_y, \
X &TempBM, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, \
X _m, -1L, NULL); \
X WaitBlit()
X
XWORD Unit;
XWORD Pattern[5] = {
X 0,
X 0x0c3f, /* Frame ....oo....oooooo */
X 0x3333, /* Char ..oo..oo..oo..oo */
X 0x1f1f, /* Word ...ooooo...ooooo */
X 0xffff /* Line oooooooooooooooo */
X};
X
XIMPORT LONG xl; /* leftmost x position */
XIMPORT LONG xr; /* rightmost x position */
XIMPORT LONG yt; /* topmost y position */
XIMPORT LONG yb; /* bottommost y position */
XLONG minx; /* left limit */
XLONG maxx; /* right limit */
XLONG maxy; /* bottom limit */
XLONG tl, tr; /* used by findword - left and right edge of word */
XWORD fw, fh; /* Font width and height used when drawing the frame */
XWORD GZZ;
XWORD SBM;
X
XIMPORT LONG mx, my; /* Mouse position in character steps */
X#define closetop 0
X#define closebottom 1
XWORD closey;
X#define closeleft 0
X#define closeright 1
XWORD closex;
X
X
Xstruct Window *window; /* The window we're snapping from */
X
X/* Data for font being snapped */
XUWORD FontHeight;
XUWORD FontWidth;
XUWORD Underscore;
XUBYTE FontType;
XUBYTE LoChar;
XUBYTE HiChar;
XUWORD Modulo;
XUWORD *CharLoc;
XUWORD NoOfChars;
XUBYTE *SrcData;
XIMPORT UBYTE *CharData;
XUBYTE IFlags;
X
XIMPORT struct RastPort TempRp, MyRP;
XIMPORT struct BitMap TempBM, MyBM;
X
XIMPORT UWORD *TempRaster; /* Used for character recognition */
X
XIMPORT struct Screen *theScreen;
XIMPORT struct RastPort rp;
Xstruct Layer *LockedLayer;
X
XIMPORT LONGBITS cancelsignal, donesignal, movesignal, clicksignal, timersignal;
XIMPORT WORD action;
X
XWORD starting;
X
X/* Init vars with font data.
X*/
X
XVOID SetSnapFont(font)
Xstruct TextFont *font;
X{
X if (!font) {
X FontWidth = -1;
X return;
X }
X FontHeight = font->tf_YSize;
X Underscore = font->tf_Baseline + 1;
X FontType = font->tf_Flags;
X FontWidth = (FontType & FPF_PROPORTIONAL ? -1 : font->tf_XSize);
X if (FontWidth == -1) {
X return;
X }
X LoChar = font->tf_LoChar;
X HiChar = font->tf_HiChar;
X Modulo = font->tf_Modulo;
X CharLoc = (UWORD *)font->tf_CharLoc;
X NoOfChars = HiChar - LoChar + 1;
X Modulo = font->tf_Modulo;
X SrcData = (UBYTE *)font->tf_CharData;
X BltClear(CharData, 256L * 32, 0L);
X WaitBlit();
X CopyFont();
X}
X
X/* Check if the character at x, y is a space
X*/
X
XWORD IsSpace(x, y)
XLONG x, y;
X{
X REGISTER WORD i = FontHeight - 1;
X REGISTER UWORD *data = &TempRaster[i];
X
X /* Copy character at x, y */
X BltClear((char *)TempRaster, 32L, 0L);
X ClipBlit(&rp, x, y,
X &TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, COPY);
X WaitBlit();
X
X if (*data) { /* Try inverted copy */
X ClipBlit(&rp, x, y,
X &TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, INVCOPY);
X WaitBlit();
X }
X while (i--) {
X if (*data--) {
X return 0;
X }
X }
X return 1;
X}
X
X#define ShortFrame 4L /* Square frame - columnar select */
X#define LongFrame 8L /* Strange frame - char or word select */
XIMPORT LONG OFType; /* Old frame type: ShortFrame/LongFrame */
XIMPORT UWORD Ptrn;
XIMPORT Point OldFrame[];
XIMPORT Point NewFrame[];
X
X
X/* update_frame calculates the new frame,
X** erases the old frame and draws the new one.
X** It's all pretty obvious if you take it slowly.
X*/
XVOID update_frame()
X{
X LONG ft;
X switch (Unit) {
X case UNIT_FRAME: {
X /*********\
X * *
X * *
X \*********/
X NewFrame[0].x = xl - 1; NewFrame[0].y = yt - 1;
X NewFrame[1].x = xr + fw; NewFrame[1].y = yt - 1;
X NewFrame[2].x = xr + fw; NewFrame[2].y = yb + fh;
X NewFrame[3].x = xl - 1; NewFrame[3].y = yb + fh;
X NewFrame[4].x = xl - 1; NewFrame[4].y = yt - 1;
X ft = ShortFrame;
X break;
X }
X case UNIT_CHAR:
X case UNIT_WORD: {
X if (yt == yb) { /* On the same line - same as UNIT_FRAME */
X NewFrame[0].x = xl - 1; NewFrame[0].y = yt - 1;
X NewFrame[1].x = xr + fw; NewFrame[1].y = yt - 1;
X NewFrame[2].x = xr + fw; NewFrame[2].y = yb + fh;
X NewFrame[3].x = xl - 1; NewFrame[3].y = yb + fh;
X NewFrame[4].x = xl - 1; NewFrame[4].y = yt - 1;
X ft = ShortFrame;
X } else {
X /*****\
X ****** *
X * *
X * *****
X *******/
X NewFrame[0].x = xl - 1; NewFrame[0].y = yt - 1;
X NewFrame[1].x = maxx + fw; NewFrame[1].y = yt - 1;
X NewFrame[2].x = maxx + fw; NewFrame[2].y = yb;
X NewFrame[3].x = xr + fw; NewFrame[3].y = yb;
X NewFrame[4].x = xr + fw; NewFrame[4].y = yb + fh;
X NewFrame[5].x = minx - 1; NewFrame[5].y = yb + fh;
X NewFrame[6].x = minx - 1; NewFrame[6].y = yt + fh;
X NewFrame[7].x = xl - 1; NewFrame[7].y = yt + fh;
X NewFrame[8].x = xl - 1; NewFrame[8].y = yt - 1;
X ft = LongFrame;
X }
X break;
X }
X case UNIT_LINE: {
X NewFrame[0].x = minx - 1; NewFrame[0].y = yt - 1;
X NewFrame[1].x = maxx + fw; NewFrame[1].y = yt - 1;
X NewFrame[2].x = maxx + fw; NewFrame[2].y = yb + fh;
X NewFrame[3].x = minx - 1; NewFrame[3].y = yb + fh;
X NewFrame[4].x = minx - 1; NewFrame[4].y = yt - 1;
X ft = ShortFrame;
X break;
X }
X default: {
X break;
X }
X }
X draw_frame(ft);
X}
X
XVOID FindWord()
X{
X /* Must remove frame to be able to search for spaces */
X WaitTOF();
X erase_frame();
X tl = mx;
X /* Find a space to the left... */
X while (!IsSpace(tl, my)) {
X tl -= fw;
X if (tl < minx) {
X break;
X }
X }
X tl += fw;
X tr = mx;
X /* ...and to the right */
X while (!IsSpace(tr, my)) {
X tr += fw;
X if (tr + fw > maxx) {
X break;
X }
X }
X tr -= fw;
X if (tr < tl) {
X tl = xl;
X tr = xr;
X }
X}
X
X/* ChangeUnit cycles the unit of selection. The differents units
X are: character, word and line.
X*/
X
XVOID ChangeUnit()
X{
X
X switch (Unit) {
X case UNIT_FRAME: {
X Unit = UNIT_CHAR;
X break;
X }
X case UNIT_CHAR: {
X Unit = UNIT_WORD;
X FindWord();
X xl = tl;
X xr = tr;
X break;
X }
X case UNIT_WORD: {
X Unit = UNIT_LINE;
X xl = minx;
X xr = maxx;
X break;
X }
X case UNIT_LINE: {
X Unit = UNIT_FRAME;
X xl = xr = mx;
X break;
X }
X }
X if (SnapRsrc->CrawlPtrn == 0) {
X Ptrn = Pattern[Unit];
X }
X}
X
X/* ExtendSelection extends the current selection according to
X the mouse position and the selected unit.
X Note that ExtendSelection doesn't optimize moves that don't
X make any difference. FIXME
X*/
X
XVOID ExtendSelection()
X{
X /* Fix which row we're talking about */
X if (closey == closetop) { /* Find closest row */
X yt = my; /* change top row */
X } else {
X yb = my; /* change bottom row */
X }
X
X /* Take care of left and right character pos */
X switch (Unit) {
X case UNIT_FRAME: {
X if (closex == closeleft) {
X xl = mx;
X } else {
X xr = mx;
X }
X break;
X }
X case UNIT_CHAR: {
X if (yt == yb) { /* One line */
X if (closex == closeleft) {
X xl = mx;
X } else {
X xr = mx;
X }
X } else { /* Multiple lines */
X if (yt == my) {
X xl = mx; /* At top - set left */
X } else {
X xr = mx; /* At bottom - set right */
X }
X }
X break;
X }
X case UNIT_WORD: {
X FindWord(); /* Find the word */
X if (yt == yb) { /* One line */
X if (closex == closeleft) { /* Find closest char pos */
X xl = tl;
X } else {
X xr = tr;
X }
X } else { /* Multiple lines */
X if (yt == my) { /* Where am I */
X xl = tl; /* At top - set left */
X } else {
X xr = tr; /* At bottom - set right */
X }
X }
X break;
X }
X case UNIT_LINE: { /* Always full width */
X break;
X }
X }
X if (yt - fh == yb) {
X yb += fh;
X }
X if (yt == yb && xl - fw == xr) {
X xr += fw;
X }
X if (xr > maxx) { /* Check for window bounds */
X xr = maxx;
X }
X if (xl < minx) { /* Check for window bounds */
X xl = minx;
X }
X if (yb > maxy) { /* Check for window bounds */
X yb = maxy;
X }
X}
X
X/* The actual character snapper. It actually works. :-) */
X
XWORD SnapChars()
X{
X LONG width;
X LONG height;
X UBYTE *SnapSpace;
X ULONG SnapSize;
X ULONG counter;
X REGISTER LONG x, y;
X
X /* Check coordinates */
X if (yt - fh == yb) { /* No rows, shouldn't happen */
X return 0;
X }
X if (yt == yb && xl - fw == xr) { /* Nothing at all */
X return 0;
X }
X
X /* Calculate stuff */
X width = maxx - (minx + 1) + fw + fw; /* Add one for a LF */
X height = yb - yt + fh;
X SnapSize = ((width / fw) + 1) * (height / fh);
X counter = 0;
X
X /* Initialize things */
X InitRastPort(&MyRP);
X InitBitMap(&MyBM, 1L, width, height);
X MyRP.BitMap = &MyBM;
X SnapSpace = AllocMem(SnapSize, MEMF_PUBLIC|MEMF_CLEAR);
X /* Please insert more memory */
X if (!SnapSpace) {
X return 0;
X }
X MyBM.Planes[0] = AllocRaster(width, height);
X if (!MyBM.Planes[0]) {
X FreeMem(SnapSpace, SnapSize);
X return 0;
X }
X IFlags = 0;
X /* Make a local copy of the snapped chars */
X ClipBlit(&rp, minx, yt, &MyRP, 0L, 0L, width, height, COPY);
X
X /* Ok, now we've got a copy of the character data */
X /* Now it's ok to mess with the layers again */
X UnlockLayer(LockedLayer);
X
X /* Clear our work area */
X BltClear((char *)TempRaster, 32L, 0L);
X
X /* Calculate bounds */
X xl -= minx;
X xr -= minx;
X maxx -= minx;
X minx = 0;
X yb -= yt;
X yt = 0;
X
X /* Single line - needs to be handled separately */
X if (yt == yb) { /* Ok, we've got one */
X
X /* Read from left to right */
X for (x = xl; x <= xr; x += fw, counter++) {
X CopyChar(x, yt, COPY);
X if ((SnapSpace[counter] = interpret(TempRaster)) == 255) {
X SnapSpace[counter] = SnapRsrc->BadChar; /* Unrecognized */
X }
X }
X if (Unit == UNIT_LINE) {
X while (counter && SnapSpace[counter-1] == ' ') {
X counter--;
X }
X }
X } else { /* Multiple lines */
X
X if (Unit == UNIT_FRAME) {
X minx = xl;
X maxx = xr;
X }
X
X /* Read first line */
X for (x = xl; x <= maxx; x += fw, counter++) {
X CopyChar(x, yt, COPY);
X if ((SnapSpace[counter] = interpret(TempRaster)) == 255) {
X SnapSpace[counter] = SnapRsrc->BadChar; /* Unrecognized */
X }
X }
X if (Unit == UNIT_FRAME) {
X SnapSpace[counter++] = 10;
X } else {
X SHORT endspace = (SnapSpace[counter-1] == ' ');
X /* Remove trailing blanks */
X while (counter && SnapSpace[counter-1] == ' ') {
X counter--;
X }
X if (endspace || !(SnapRsrc->flags & JOINLONG)) {
X SnapSpace[counter++] = 10;
X }
X }
X
X /* If more than two rows - read full middle rows */
X if (yt + fh != yb) {
X for (y = yt + fh; y < yb; y += fh) {
X for (x = minx; x <= maxx; x += fw, counter++) {
X CopyChar(x, y, COPY);
X if ((SnapSpace[counter] = interpret(TempRaster)) == 255) {
X SnapSpace[counter] = SnapRsrc->BadChar; /* Unrecognized */
X }
X }
X if (Unit == UNIT_FRAME) {
X SnapSpace[counter++] = 10;
X } else {
X SHORT endspace = (SnapSpace[counter-1] == ' ');
X /* Remove trailing blanks */
X while (counter && SnapSpace[counter-1] == ' ') {
X counter--;
X }
X if (endspace || !(SnapRsrc->flags & JOINLONG)) {
X SnapSpace[counter++] = 10;
X }
X }
X }
X }
X
X /* Read last line */
X for (x = minx; x <= xr; x += fw, counter++) {
X CopyChar(x, yb, COPY);
X if ((SnapSpace[counter] = interpret(TempRaster)) == 255) {
X SnapSpace[counter] = SnapRsrc->BadChar; /* Unrecognized */
X }
X }
X /* Remove trailing blanks */
X while (counter && SnapSpace[counter-1] == ' ') {
X counter--;
X }
X }
X FreeRaster(MyBM.Planes[0], width, height);
X SaveClip(SnapSpace, counter);
X FreeMem(SnapSpace, SnapSize);
X return 1;
X}
X
X
X/* HandleChars is the part of the Snap state machine that handles
X snapping of characters. The selection is done in different
X units: char, word, line.
X*/
X
XWORD HandleChars()
X{
X LONG xoff, yoff;
X LONG ox, oy;
X
X /* Find out which screen we're working on */
X theScreen = WhichScreen();
X
X /* Oops, no screen? */
X if (!theScreen) {
X action = noaction;
X return 0;
X }
X
X /* Ok, what window? */
X window = WhichWindow(theScreen);
X
X /* Oh dear, no window. */
X if (!window) {
X action = noaction;
X return 0;
X }
X
X /* No messing with the layers while I think */
X LockedLayer = window->WLayer;
X LockLayer(0L, LockedLayer);
X
X /* Don't want to wreck somebody's rastport */
X CopyMem((char *)window->RPort, (char *)&rp, (LONG)sizeof(struct RastPort));
X
X /* Or his picture */
X SetDrMd(&rp, COMPLEMENT);
X rp.Mask = SnapRsrc->FrameMask;
X
X /* Find out what we're trying to read */
X SetSnapFont(rp.Font);
X if (FontWidth == -1) {
X UnlockLayer(LockedLayer);
X action = noaction;
X return 0;
X }
X
X if (window->Flags & GIMMEZEROZERO) {
X GZZ = 1;
X } else {
X GZZ = 0;
X }
X if (window->Flags & SUPER_BITMAP) {
X SBM = 1;
X } else {
X SBM = 0;
X }
X
X /* Find a position */
X xl = (GZZ ? window->GZZMouseX : window->MouseX)
X + window->RPort->Layer->Scroll_X;
X yt = (GZZ ? window->GZZMouseY : window->MouseY)
X + window->RPort->Layer->Scroll_Y;
X
X if (xl < 0) {
X xl = 0;
X }
X if (yt < 0) {
X yt = 0;
X }
X
X /* Check your position */
X if (xl > (GZZ ? window->GZZWidth : window->Width) ||
X yt > (GZZ ? window->GZZHeight : window->Height)) {
X UnlockLayer(LockedLayer);
X action = noaction;
X return 0;
X }
X IFlags = 0;
X
X /* Find out the offset for the clicked character, if any.
X ** This is the part that makes it special. Simple, isn't it. Hah!
X */
X {
X REGISTER struct CacheWindow *cw = GetCachedWindow(theScreen, window);
X
X if (cw) {
X xoff = - ((xl - cw->xoff) % cw->fw);
X yoff = - ((yt - cw->yoff) % cw->fh);
X BltClear((char *)TempRaster, 32L, 0L);
X ClipBlit(&rp, xl + xoff, yt + yoff,
X &TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, COPY);
X WaitBlit();
X if (interpret(TempRaster) != 255) {
X goto found;
X }
X }
X /* No cache or cache didn't match */
X xl -= 7;
X yt -= 7;
X BltClear((char *)TempRaster, 32L, 0L);
X xoff = 0;
X while (xoff < (16 - FontWidth)) {
X ClipBlit(&rp, xl + xoff, yt,
X &TempRp, 0L, 0L, (LONG)FontWidth, 16L, COPY);
X WaitBlit();
X yoff = 0;
X while (yoff < (16 - FontHeight)) {
X if (interpret(&TempRaster[yoff]) != 255) {
X goto found;
X }
X ++yoff;
X }
X ++xoff;
X }
X
X /* No character found. Back off */
X UnlockLayer(LockedLayer);
X action = noaction;
X return 0;
X
Xfound:
X /* Ok, now we know where to look for chars.
X ** xoff and yoff is character position within our 16x16 bitmap.
X */
X xl = xl + xoff; /* Adjust x */
X yt = yt + yoff; /* Adjust y */
X
X fw = FontWidth;
X fh = FontHeight;
X
X {
X SHORT temp = fh;
X while (temp <= fh + 1) { /* Check for extra pixel row */
X BltClear((char *)TempRaster, 32L, 0L);
X ClipBlit(&rp, xl, yt + temp,
X &TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, COPY);
X WaitBlit();
X if (interpret(TempRaster) != 255) {
X fh = temp;
X break;
X }
X ++temp;
X }
X }
X
X /* Find out offsets within the window */
X xoff = xl % fw;
X yoff = yt % fh;
X
X if (cw) {
X cw->xoff = xoff;
X cw->yoff = yoff;
X cw->fw = fw;
X cw->fh = fh;
X } else {
X CacheWindow(window, xoff, yoff, fw, fh);
X }
X }
X
X /* Set bounds */
X minx = xoff;
X maxx = minx +
X (((GZZ ?
X window->GZZWidth :
X window->Width - window->BorderRight
X /* Hack for borderless conman windows */
X + (window->Flags & BORDERLESS && window->Flags & WINDOWSIZING ? 14 : 0))
X - minx - fw) / fw) * fw;
X maxy = ((GZZ ? window->GZZHeight : window->Height) / fh) * fh;
X
X /* Check bounds */
X if (xl > maxx) {
X UnlockLayer(LockedLayer);
X action = noaction;
X return 0;
X }
X /* Set box dimensions */
X xr = xl;
X yb = yt;
X ox = xr;
X oy = yt;
X
X /* Select unit while starting */
X starting = 1;
X
X /* Starting unit is character or frame */
X Unit = SnapRsrc->StartUnit;
X Ptrn = (SnapRsrc->CrawlPtrn ? SnapRsrc->CrawlPtrn : Pattern[Unit]);
X OFType = 0L;
X update_frame();
X
X /* Get the state machine running */
X FOREVER {
X /* Wait for something to happen */
X REGISTER LONGBITS sig =
X Wait(movesignal|cancelsignal|donesignal|clicksignal|timersignal);
X
X if ((sig & timersignal) && (SnapRsrc->CrawlPtrn != 0xffff)) {
X crawl_frame(0L);
X }
X
X mx = (LONG)(GZZ ? window->GZZMouseX : window->MouseX)
X + window->RPort->Layer->Scroll_X;
X if (mx < 0) {
X mx = 0;
X }
X /* Calculate which edge is closest */
X if ((mx - xl) < (xr - mx)) {
X closex = closeleft;
X } else {
X closex = closeright;
X }
X /* Only interested in real char pos */
X mx = mx - ((mx - xoff) % fw);
X
X my = (LONG)(GZZ ? window->GZZMouseY : window->MouseY)
X + window->RPort->Layer->Scroll_Y;
X if (my < 0) {
X my = 0;
X }
X /* Calculate which row is closest */
X if ((my - yt) < (yb - my)) {
X closey = closetop;
X } else {
X closey = closebottom;
X }
X my = my - ((my - yoff) % fh);
X
X /* Hey, it moves! It's alive!! */
X if ((sig & movesignal) && (action == snaptext)) {
X if (mx != ox || my != oy) { /* Something's happened */
X ExtendSelection();
X update_frame();
X starting = 0;
X ox = mx;
X oy = my;
X sig &= ~clicksignal;
X }
X }
X
X /* Ok, forget it... */
X if (sig & cancelsignal) {
X erase_frame();
X UnlockLayer(LockedLayer);
X return 0;
X }
X
X /* Click */
X if ((sig & clicksignal) && (action == snaptext)) {
X /* Selecting unit */
X if (starting) {
X if (mx == ox && my == oy) {
X ChangeUnit();
X if (Unit == UNIT_CHAR) {
X ChangeUnit();
X }
X update_frame();
X } else if (Unit == UNIT_FRAME) {
X ChangeUnit();
X update_frame();
X }
X }
X if (mx != ox || my != oy) { /* Click in a new place */
X ExtendSelection();
X update_frame();
X starting = 0;
X ox = mx;
X oy = my;
X }
X }
X
X /* Finished */
X if (sig & donesignal) {
X erase_frame();
X return SnapChars();
X }
X }
X}
X
END_OF_FILE
if test 21526 -ne `wc -c <'source/snapchars.c'`; then
echo shar: \"'source/snapchars.c'\" unpacked with wrong size!
fi
# end of 'source/snapchars.c'
fi
echo shar: End of archive 3 \(of 4\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 4 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
Mail submissions (sources or binaries) to <amiga@cs.odu.edu>.
Mail comments to the moderator at <amiga-request@cs.odu.edu>.
Post requests for sources, and general dicussion to comp.sys.amiga.